import type { EventHookOn, Fn } from '@vueuse/core';
import { createEventHook, useRafFn } from '@vueuse/core';
import type { Ref } from 'vue';
import { Clock } from 'three';

export interface RenderLoop {
    delta: number;
    elapsed: number;
    clock: Clock;
}

export interface UseRenderLoopReturn {
    onBeforeLoop: EventHookOn<RenderLoop>;
    onLoop: EventHookOn<RenderLoop>;
    onAfterLoop: EventHookOn<RenderLoop>;
    pause: Fn;
    resume: Fn;
    isActive: Ref<boolean>;
}

const onBeforeLoop = createEventHook<RenderLoop>();
const onLoop = createEventHook<RenderLoop>();
const onAfterLoop = createEventHook<RenderLoop>();

const clock = new Clock();
let delta = 0;
let elapsed = 0;

const { pause, resume, isActive } = useRafFn(
    () => {
        onBeforeLoop.trigger( { delta, elapsed, clock } );
        onLoop.trigger( { delta, elapsed, clock } );
        onAfterLoop.trigger( { delta, elapsed, clock } );
    },
    { immediate: false },
);

onAfterLoop.on( () => {
    delta = clock.getDelta();
    elapsed = clock.getElapsedTime();
} );

export const useRenderLoop = (): UseRenderLoopReturn => ( {
    onBeforeLoop: onBeforeLoop.on,
    onLoop: onLoop.on,
    onAfterLoop: onAfterLoop.on,
    pause,
    resume,
    isActive,
} );
